package com.atguigu.service.impl;

import com.atguigu.constant.RedisConst;
import com.atguigu.entity.PrepareSeckillOrder;
import com.atguigu.entity.SeckillProduct;
import com.atguigu.entity.UserSeckillSkuInfo;
import com.atguigu.mapper.SeckillProductMapper;
import com.atguigu.result.RetVal;
import com.atguigu.result.RetValCodeEnum;
import com.atguigu.service.SeckillProductService;
import com.atguigu.util.MD5;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zhangqiang
 * @since 2022-01-21
 */
@Service
public class SeckillProductServiceImpl extends ServiceImpl<SeckillProductMapper, SeckillProduct> implements SeckillProductService {
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public SeckillProduct querySeckillProductById(Long skuId) {
        return (SeckillProduct) redisTemplate.opsForHash().get(RedisConst.SECKILL_PRODUCT, skuId.toString());
    }

    @Override
    public void prepareSecKill(UserSeckillSkuInfo userSeckillSkuInfo) {
        Long skuId = userSeckillSkuInfo.getSkuId();
        String userId = userSeckillSkuInfo.getUserId();
        //a.秒杀商品是否可以进行秒杀 状态是否为1  seckill:state:24
        String state = (String) redisTemplate.opsForValue().get(RedisConst.SECKILL_STATE_PREFIX + skuId);
        //商品已经售罄
        if (RedisConst.CAN_NOT_SECKILL.equals(state)) {
            return;
        }
        //b.判断该用户是否下过该订单
        boolean flag = redisTemplate.opsForValue().setIfAbsent(RedisConst.PREPARE_SECKILL_USERID_SKUID + ":" + userId + ":" + skuId, skuId, RedisConst.PREPARE_SECKILL_LOCK_TIME, TimeUnit.SECONDS);
        if (!flag) {
            return;
        }
        //c.校验是否还有库存 如果有库存 需要减库存 seckill:stock:24
        String redisStockSkuId = (String) redisTemplate.boundListOps(RedisConst.SECKILL_STOCK_PREFIX + skuId).rightPop();
        //没有库存
        if (StringUtils.isEmpty(redisStockSkuId)) {
            //通知并修改秒杀状态位
            redisTemplate.convertAndSend(RedisConst.PREPARE_PUB_SUB_SECKILL, skuId + ":" + RedisConst.CAN_NOT_SECKILL);
            return;
        }
        //d.生成临时订单数据到redis中
        PrepareSeckillOrder prepareSeckillOrder = new PrepareSeckillOrder();
        prepareSeckillOrder.setUserId(userId);
        prepareSeckillOrder.setBuyNum(1);
        SeckillProduct seckillProduct = querySeckillProductById(skuId);
        prepareSeckillOrder.setSeckillProduct(seckillProduct);
        //设置订单码
        prepareSeckillOrder.setPrepareOrderCode(MD5.encrypt(userId + skuId));
        redisTemplate.boundHashOps(RedisConst.PREPARE_SECKILL_USERID_ORDER).put(userId, prepareSeckillOrder);
        //更新库存量
        updateSecKillStockCount(skuId);


    }

    //更新库存信息
    private void updateSecKillStockCount(Long skuId) {
        //剩余库存量
        Long leftStock = redisTemplate.boundListOps(RedisConst.SECKILL_STOCK_PREFIX + skuId).size();
        //更新数据库频次 自定义一个规则
        if (leftStock % 2 == 0) {
            SeckillProduct seckillProduct = querySeckillProductById(skuId);
            //锁定库存数=总商品数量-剩余库存量
            Integer totalStock = seckillProduct.getNum();
            int lockStock = totalStock - Integer.parseInt(leftStock + "");
            seckillProduct.setStockCount(lockStock);
            //更新数据库为了持久化 防止数据丢失
            baseMapper.updateById(seckillProduct);
            //更新redis的已售商品数量信息 目的为了给使用客户看还剩多少库存
            redisTemplate.boundHashOps(RedisConst.SECKILL_PRODUCT).put(skuId.toString(), seckillProduct);
        }

    }

    @Override
    public RetVal hasQualified(Long skuId, String userId) {
        //1.如果预下单中有用户信息 就代表有抢购资格
        boolean isExist = redisTemplate.hasKey(RedisConst.PREPARE_SECKILL_USERID_SKUID + ":" + userId + ":" + skuId);
        if (isExist) {
            /**
             * prepareSeckillOrder 如果为空 代表用户已经购买过该商品 因为后面购买成功之后我们要删除该预购信息
             * prepareSeckillOrder 如果不为空 代表用户抢单成功 具备抢购资格
             */
            PrepareSeckillOrder prepareSeckillOrder = (PrepareSeckillOrder)redisTemplate.boundHashOps(RedisConst.PREPARE_SECKILL_USERID_ORDER).get(userId);
            if(prepareSeckillOrder!=null){
                return RetVal.build(prepareSeckillOrder, RetValCodeEnum.PREPARE_SECKILL_SUCCESS);
            }
        }
        //TODO 明天写
        Integer orderId=(Integer) redisTemplate.boundHashOps(RedisConst.BOUGHT_SECKILL_USER_ORDER).get(userId);
        if(orderId!=null){
            return RetVal.build(orderId,RetValCodeEnum.SECKILL_ORDER_SUCCESS);
        }
        return RetVal.build(null,RetValCodeEnum.SECKILL_RUN);
    }
}
